import * as Cesium from 'cesium'

export default class MeasureTool {
    constructor(viewer) {
        this.viewer = viewer // Cesium 实例
        this.handler = null // 事件处理器
        this.points = [] // 测量点集合
        this.entities = [] // 绘制实体集合
        this.currentType = null // 当前测量类型
    }

    /**
     * 清除所有测量结果
     */
    clear() {
        this.points = [];
        // 移除所有实体
        this.entities.forEach(entity => {
            this.viewer.entities.remove(entity);
        });
        this.entities = [];
        // 销毁 handler 前先判断是否存在且未被销毁
        if (this.handler) {
            // 尝试销毁（若已销毁，Cesium 可能会抛错，用 try/catch 捕获）
            try {
                this.handler.destroy();
            } catch (e) {
                console.warn('Handler 已销毁，无需重复操作');
            }
            this.handler = null; // 无论是否销毁成功，均重置为 null
        }
        this.currentType = null;
    }

    
    /**
     * 开始长度测量
     */
    measureLength() {
        this.clear()
        this.currentType = 'length'
        this._initDrawHandler()

        // 左键点击添加点
        this.handler.setInputAction(movement => {
            const cartesian = this._getCartesianFromMouse(movement.position)
            if (!cartesian) return

            this.points.push(cartesian)
            this._createPointEntity(cartesian)

            // 至少2个点时绘制线并计算长度
            if (this.points.length >= 2) {
                this._updateLineEntity()
                this._calculateLength()
            }
        }, Cesium.ScreenSpaceEventType.LEFT_CLICK)

        // 鼠标移动时预览线
        this._addMouseMovePreview()

        // 右键结束测量
        this._addRightClickFinish()
    }

    /**
     * 开始面积测量
     */
    measureArea() {
        this.clear()
        this.currentType = 'area'
        this._initDrawHandler()

        // 左键点击添加点
        this.handler.setInputAction(movement => {
            const cartesian = this._getCartesianFromMouse(movement.position)
            if (!cartesian) return

            this.points.push(cartesian)
            this._createPointEntity(cartesian)

            // 至少3个点时绘制多边形并计算面积
            if (this.points.length >= 3) {
                this._updatePolygonEntity()
                this._calculateArea()
            }
        }, Cesium.ScreenSpaceEventType.LEFT_CLICK)

        // 鼠标移动时预览多边形
        this._addMouseMovePreview()

        // 右键结束测量
        this._addRightClickFinish()
    }

    /**
     * 开始高度测量（两点高差）
     */
    measureHeight() {
        this.clear(); // 先清除之前的状态（关键：确保 handler 已重置）
        this.currentType = 'height';
        this._initDrawHandler(); // 重新初始化 handler

        // 左键点击添加点（最多2个点）
        this.handler.setInputAction(movement => {
            const cartesian = this._getCartesianFromMouse(movement.position);
            if (!cartesian) return;

            this.points.push(cartesian);
            this._createPointEntity(cartesian);

            // 2个点时计算高差并结束
            if (this.points.length === 2) {
                this._updateLineEntity();
                this._calculateHeightDiff();
                // 销毁 handler 后必须置为 null，避免后续操作已销毁对象
                this.handler.destroy();
                this.handler = null; // 关键修复：重置 handler
            }
        }, Cesium.ScreenSpaceEventType.LEFT_CLICK);

        // 右键取消测量（补充右键逻辑，确保可中途退出）
        this.handler.setInputAction(() => {
            this.clear(); // 调用 clear 统一清理
        }, Cesium.ScreenSpaceEventType.RIGHT_CLICK);
    }

    /**
     * 初始化事件处理器
     */
    _initDrawHandler() {
        this.handler = new Cesium.ScreenSpaceEventHandler(this.viewer.canvas)
    }

    /**
     * 从鼠标位置获取笛卡尔坐标
     */
    _getCartesianFromMouse(position) {
        // 尝试从椭球面拾取
        let cartesian = this.viewer.camera.pickEllipsoid(
            position,
            this.viewer.scene.globe.ellipsoid
        )

        // 若椭球面拾取失败，尝试从地形拾取
        if (!cartesian) {
            const ray = this.viewer.camera.getPickRay(position)
            cartesian = this.viewer.scene.globe.pick(ray, this.viewer.scene)
        }

        return cartesian
    }

    /**
     * 创建点实体
     */
    _createPointEntity(cartesian) {
        const point = this.viewer.entities.add({
            position: cartesian,
            point: {
                color: Cesium.Color.RED,
                pixelSize: 8,
                outlineColor: Cesium.Color.WHITE,
                outlineWidth: 2
            }
        })
        this.entities.push(point)
    }

    /**
     * 更新线实体
     */
    _updateLineEntity() {
        // 移除上一次的线实体
        if (this._getLastEntityByType('polyline')) {
            this.viewer.entities.remove(this._getLastEntityByType('polyline'))
            this.entities.pop()
        }

        const line = this.viewer.entities.add({
            polyline: {
                positions: this.points,
                width: 3,
                material: new Cesium.PolylineGlowMaterialProperty({
                    glowPower: 0.2,
                    color: Cesium.Color.YELLOW
                }),
                clampToGround: true
            }
        })
        this.entities.push(line)
    }

    /**
     * 更新多边形实体
     */
    _updatePolygonEntity() {
        // 查找已存在的多边形实体（如果有则更新，没有则创建）
        let polygonEntity = this.entities.find(entity => entity.polygon);

        if (polygonEntity) {
            // 更新已有多边形的坐标
            polygonEntity.polygon.hierarchy = new Cesium.PolygonHierarchy(this.points);
        } else {
            // 创建新的多边形实体
            polygonEntity = this.viewer.entities.add({
                polygon: {
                    hierarchy: new Cesium.PolygonHierarchy(this.points),
                    material: Cesium.Color.RED.withAlpha(0.5),
                    outline: true,
                    outlineColor: Cesium.Color.RED,
                    outlineWidth: 2,
                    clampToGround: true
                }
            });
            this.entities.push(polygonEntity);
        }
    }

    /**
 * 添加鼠标移动预览（优化版）
 */
    _addMouseMovePreview() {
        this.handler.setInputAction(movement => {
            if (this.points.length === 0) return;

            const tempPoint = this._getCartesianFromMouse(movement.endPosition);
            if (!tempPoint) return;

            // 临时点集合（包含已有点+当前鼠标点）
            const tempPoints = [...this.points, tempPoint];

            // 查找已有的预览多边形实体
            let previewEntity = this.entities.find(entity =>
                entity.polygon && entity._preview // 标记预览实体
            );

            // 如果是面积测量且已有至少2个点
            if (this.currentType === 'area' && this.points.length >= 2) {
                if (previewEntity) {
                    // 更新预览多边形坐标
                    previewEntity.polygon.hierarchy = new Cesium.PolygonHierarchy(tempPoints);
                } else {
                    // 创建新的预览多边形（标记为_preview）
                    previewEntity = this.viewer.entities.add({
                        _preview: true, // 自定义标记，用于区分预览实体
                        polygon: {
                            hierarchy: new Cesium.PolygonHierarchy(tempPoints),
                            material: Cesium.Color.RED.withAlpha(0.5),
                            outline: true,
                            outlineColor: Cesium.Color.RED,
                            clampToGround: true
                        }
                    });
                    this.entities.push(previewEntity);
                }
            } else if (previewEntity) {
                // 不需要预览时移除预览实体
                this.viewer.entities.remove(previewEntity);
                this.entities = this.entities.filter(e => e !== previewEntity);
            }
        }, Cesium.ScreenSpaceEventType.MOUSE_MOVE);
    }

    /**
 * 添加右键结束事件（优化版）
 */
    _addRightClickFinish() {
        this.handler.setInputAction(() => {
            // 移除预览实体
            this.entities = this.entities.filter(entity => {
                if (entity._preview) {
                    this.viewer.entities.remove(entity);
                    return false;
                }
                return true;
            });
            // 重置处理器（改为调用 clear 方法统一管理）
            this.clear();
        }, Cesium.ScreenSpaceEventType.RIGHT_CLICK);
    }

    /**
     * 计算长度
     */
    _calculateLength() {
        // 移除上一次的标签
        this._removeLastLabel()

        let totalLength = 0
        for (let i = 1; i < this.points.length; i++) {
            totalLength += Cesium.Cartesian3.distance(this.points[i - 1], this.points[i])
        }

        // 显示长度标签
        const label = this.viewer.entities.add({
            position: this.points[this.points.length - 1],
            label: this._getLabelStyle(`总长: ${totalLength.toFixed(2)}米`)
        })
        this.entities.push(label)
    }

    /**
 * 计算面积（兼容所有Cesium版本的方案）
 */
    _calculateArea() {
        this._removeLastLabel()

        // 1. 将笛卡尔坐标转换为经纬度（度）
        const coordinates = this.points.map(cartesian => {
            const cartographic = Cesium.Cartographic.fromCartesian(cartesian)
            return [
                Cesium.Math.toDegrees(cartographic.longitude), // 经度（度）
                Cesium.Math.toDegrees(cartographic.latitude)   // 纬度（度）
            ]
        })

        // 2. 使用高斯-克吕格投影（UTM）将经纬度转换为平面坐标（米）
        // 取第一个点的经度确定投影带
        const firstLon = coordinates[0][0]
        const zone = Math.floor((firstLon + 180) / 6) + 1 // 计算UTM投影带

        // 转换所有点为平面坐标
        const planarPoints = coordinates.map(([lon, lat]) => {
            const isNorthern = lat >= 0 // 北半球/南半球
            const utmCoords = this._latLonToUtm(lat, lon, zone, isNorthern)
            return { x: utmCoords.easting, y: utmCoords.northing }
        })

        // 3. 计算平面多边形面积（平方米）
        const area = this._calculatePlanarArea(planarPoints)

        // 4. 转换为平方公里并显示
        const areaKm2 = (area / 1000000).toFixed(4)
        const center = this._getPolygonCenter()
        const label = this.viewer.entities.add({
            position: center,
            label: this._getLabelStyle(`面积: ${areaKm2} 平方公里`)
        })
        this.entities.push(label)
    }
    /**
 * 经纬度转UTM平面坐标（米）
 * @param {number} lat 纬度（度）
 * @param {number} lon 经度（度）
 * @param {number} zone UTM投影带
 * @param {boolean} isNorthern 是否北半球
 * @returns {object} {easting: 东向距离, northing: 北向距离}
 */
    _latLonToUtm(lat, lon, zone, isNorthern) {
        const a = 6378137.0; // WGS84长半轴
        const f = 1 / 298.257223563; // 扁率
        const k0 = 0.9996; // 比例因子

        const latRad = Cesium.Math.toRadians(lat);
        const lonRad = Cesium.Math.toRadians(lon);
        const lonOriginRad = Cesium.Math.toRadians((zone - 1) * 6 - 180 + 3); // 中央经线

        const N = a / Math.sqrt(1 - f * (2 - f) * Math.sin(latRad) ** 2);
        const T = Math.tan(latRad) ** 2;
        const C = (f * (2 - f) / (1 - f) ** 2) * Math.cos(latRad) ** 2;
        const A = (lonRad - lonOriginRad) * Math.cos(latRad);

        // 计算东向距离（Easting）
        const M = a * ((1 - f / 4 - 3 * f ** 2 / 64 - 5 * f ** 3 / 256) * latRad
            - (3 * f / 8 + 3 * f ** 2 / 32 + 45 * f ** 3 / 1024) * Math.sin(2 * latRad)
            + (15 * f ** 2 / 256 + 45 * f ** 3 / 1024) * Math.sin(4 * latRad)
            - (35 * f ** 3 / 3072) * Math.sin(6 * latRad));

        const easting = k0 * N * (A + (1 - T + C) * A ** 3 / 6
            + (5 - 18 * T + T ** 2 + 72 * C - 58 * f ** 2) * A ** 5 / 120) + 500000;

        // 计算北向距离（Northing）
        const northing = k0 * (M + N * Math.tan(latRad) * (A ** 2 / 2
            + (5 - T + 9 * C + 4 * C ** 2) * A ** 4 / 24
            + (61 - 58 * T + T ** 2 + 600 * C - 330 * f ** 2) * A ** 6 / 720));

        // 南半球需减去10000公里
        return {
            easting: easting,
            northing: isNorthern ? northing : northing + 10000000
        };
    }

    /**
     * 计算平面多边形面积（平方米）
     * @param {array} points 平面坐标数组 [{x, y}, ...]
     * @returns {number} 面积
     */
    _calculatePlanarArea(points) {
        let area = 0;
        const n = points.length;
        for (let i = 0; i < n; i++) {
            const j = (i + 1) % n;
            area += points[i].x * points[j].y;
            area -= points[j].x * points[i].y;
        }
        return Math.abs(area / 2);
    }

    /**
     * 计算高度差
     */
    _calculateHeightDiff() {
        // 移除上一次的标签
        this._removeLastLabel()

        // 转换为地理坐标（包含高度）
        const carto1 = Cesium.Cartographic.fromCartesian(this.points[0])
        const carto2 = Cesium.Cartographic.fromCartesian(this.points[1])

        // 计算高差（绝对值）
        const diff = Math.abs(carto2.height - carto1.height).toFixed(2)

        // 在两点中间显示标签
        const midPoint = Cesium.Cartesian3.lerp(
            this.points[0],
            this.points[1],
            0.5,
            new Cesium.Cartesian3()
        )

        const label = this.viewer.entities.add({
            position: midPoint,
            label: this._getLabelStyle(`高差: ${diff} 米`)
        })
        this.entities.push(label)
    }

    /**
     * 获取多边形中心
     */
    _getPolygonCenter() {
        const sum = this.points.reduce(
            (acc, point) => {
                acc.x += point.x
                acc.y += point.y
                acc.z += point.z
                return acc
            },
            { x: 0, y: 0, z: 0 }
        )
        return new Cesium.Cartesian3(
            sum.x / this.points.length,
            sum.y / this.points.length,
            sum.z / this.points.length
        )
    }

    /**
     * 获取标签样式
     */
    _getLabelStyle(text) {
        return {
            text: text,
            font: '16px Microsoft YaHei',
            fillColor: Cesium.Color.WHITE,
            backgroundColor: Cesium.Color.BLACK.withAlpha(0.7),
            padding: new Cesium.Cartesian2(8, 4),
            pixelOffset: new Cesium.Cartesian2(0, -30),
            horizontalOrigin: Cesium.HorizontalOrigin.CENTER
        }
    }

    /**
     * 移除上一次的标签实体
     */
    _removeLastLabel() {
        // 过滤并移除所有标签实体
        this.entities = this.entities.filter(entity => {
            if (entity.label) {
                this.viewer.entities.remove(entity);
                return false;
            }
            return true;
        });
    }

    /**
     * 获取最后一个指定类型的实体
     */
    _getLastEntityByType(type) {
        if (this.entities.length === 0) return null
        const last = this.entities[this.entities.length - 1]
        if (type === 'polyline' && last.polyline) return last
        if (type === 'polygon' && last.polygon) return last
        if (type === 'preview' && (last.polyline || last.polygon)) return last
        return null
    }
}